#include <iostream>
#include "sockdist.h"
#include "sock.h"
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
# include <sys/ipc.h>
#include <sys/shm.h>

using namespace std;

#include "ServeurTCP.h"


ServeurTCP::ServeurTCP(){
}

ServeurTCP::ServeurTCP(int p,int t,ActionListenner* l):Hote(p,t,l){

  	// Demande de BR Publique
  	Sock brPub(SOCK_STREAM,(short)Hote::port,0);

  	// On recupere le descripteur
  	if(brPub.good()) {
    	Hote::descBrLocale = brPub.getsDesc(); 

    	cout << "# Demande de BR locale : OK" << endl;
  	}

  	else {
    	cout << "# Erreur : Probleme BR Locale" << endl;
    	exit(1);
  	} 

  	//file d'attente
  	int FA = listen(Hote::descBrLocale,10);

  	if(FA == -1){
    	perror("# File d'attente");
    	exit(EXIT_FAILURE);
  	}
  	else {
    	cout<<"# File d'attente initialisée"<<endl;
  	}

}

int ServeurTCP::accepter(){

  	//accept
  	Hote::lgBrDistante = sizeof(struct sockaddr_in);
  	cout << "# Serveur en attente d'une connexion..."<< endl;

  	int descBrCv = accept (Hote::descBrLocale,(struct sockaddr *)&adrBrDistante,&lgBrDistante);

  	if(descBrCv == -1){
    	perror("# Accept");
    	//exit(EXIT_FAILURE);
  	}
  	else {
    	cout<<"# Accept : ok"<<endl;
  	}
   	return descBrCv;
}


void ServeurTCP::envoyer(string t, int descBrCv){
  	//envoie
  	tamponSnd = conversionStringChar(t);

  	int retourSend = send(descBrCv,tamponSnd,Hote::tailleTampon,0);

  	if (retourSend == -1){
    	perror("# Send ");
    	exit(EXIT_FAILURE);
  	}
  	else if(retourSend == 0){
    	perror("# Circuit virtuel coupe : send");
    	exit(EXIT_FAILURE);
  	}
  	//else cout<<"# Message envoye"<<endl;

}

string ServeurTCP::recevoir(int descBrCv){

  	int retourRecv = recv(descBrCv,tamponRcv,Hote::tailleTampon,0 );

  	if (retourRecv== -1){
    	perror("# Recv ");
    	close(descBrCv);
		return "#1";
  	}

  	else if(retourRecv == 0){

    	perror("# Circuit virtuel coupe : recv");
    	close(descBrCv);
		return "#0";
  	}

  	else{
    	return conversionCharString(tamponRcv);
  	}
}

void* ServeurTCP::fonctionThread(void * a){


    argThread* arg =(argThread*) a;
  	int desc =(int)arg->descBrCv;
  	ServeurTCP* serveurTCP = arg->serveur;
  	pthread_mutex_t verrou = arg->verrou;

  	//obtention de la clé
  	int cleMem = ftok ("./cle.txt",1);
  	if(cleMem == 0){
    	cout<<"Impossible de creer la Clef memoire. "<<cleMem<<endl;
    	exit(-1);
  	}
  	else {
    	cout<<"Calcul de la clef memoire reussit. "<< cleMem<<endl;
  	}

  	// acces a l'espace memoire partagée
  	int laMem = shmget(cleMem,(10+1)*sizeof(int), 0600);
  	if(laMem ==  0){
    	cout<<"impossible de creer la memoire partagée."<<laMem<<endl;
    	exit(-1);
  	}
  	else {
    	cout<<"la Memoire Partagée a bien ete cree. "<<laMem<<endl;
  	}

  	//demande d'acces à la memoire partagée par le proc
  	int * p_att;
  	p_att=(int*) shmat(laMem,NULL,0);
  	if(*p_att == -1){
    	cout<<"impossible d'acceder a l'espace memoire pour le proc :"<<getpid()<<endl;
    	exit(-1);
  	}
  	else {
    	cout<<"Acces à l'espace memoire réussit pour le proc: "<<getpid()<<endl;
  	}

  	int numAction = 1;
  	bool exit = false;
  	while(!exit){
	ActionListenner * l = serveurTCP->listenner;
      	string action = l->getAction(numAction, (int)desc);
      	serveurTCP->envoyer(action,desc);
      	if(numAction!=-1){
      	  	string reponse = serveurTCP->recevoir(desc);
	  	  	if(reponse== "#0"){//CV coupé
			  	exit = true;
	  	  	} else if (reponse != "#1"){
      		  	pthread_mutex_lock(&verrou);
      		  	numAction = serveurTCP->listenner->action(numAction,reponse, desc);
      		  	pthread_mutex_unlock(&verrou);
	  	  	}
      	}
      	else
      	  	exit = true;
  	}
  	cout<<"Le client "<<desc<<" s'est deconnecte"<<endl;
  	close(desc);
  	pthread_mutex_destroy(&verrou);
  	pthread_exit(NULL);


}

void ServeurTCP::creationThread(int desc){

  	//thread
  	pthread_t p;
  	cout<<"# Thread créé"<<endl;

  	//verrou initialisé au mode " dévérouillé"
  	pthread_mutex_t leVerrou;
  	pthread_mutex_unlock(&leVerrou);
  	cout<<"# Verrou créé et initialisée..."<<endl;

  	argThread * arg = new argThread;
  	arg->serveur = this;
  	arg->descBrCv = desc;
  	arg->verrou = leVerrou;

  	int retourthread = pthread_create(&p,NULL,ServeurTCP::fonctionThread,(void*)arg);

  	if(retourthread < 0){
    	perror("# Thread");
    	//exit(EXIT_FAILURE);

  	}

  	//(void)pthread_join(p,NULL);
}

